
package com.idealighter.game.games.zjh.manager;

import com.google.inject.Inject;
import com.google.inject.Singleton;

import com.idealighter.game.dictionary.dic.ZhajinhuaRoomTypeDic;
import com.idealighter.game.dictionary.domain.ZhajinhuaRoomDomain;
import com.idealighter.game.dictionary.domwrapper.ZhajinhuaRoomDomWrapper;
import com.idealighter.game.gamehall.dto.MemInfo;
import com.idealighter.game.games.common.AbstractRoom;
import com.idealighter.game.games.common.AbstractSeat;
import com.idealighter.game.games.common.AbstractTable;
import com.idealighter.game.games.common.RoomState;
import com.idealighter.game.games.zjh.dto.GameInfo;
import com.idealighter.game.games.zjh.dto.GameInfo.MySelfCard;
import com.idealighter.game.games.zjh.dto.GameInfo.PlayerItem;
import com.idealighter.game.games.zjh.dto.GameInfo.PlayerItem.PlayerStatus;
import com.idealighter.game.games.zjh.dto.RoomInfo;
import com.idealighter.game.games.zjh.dto.RoomTypeDetailInfo;
import com.idealighter.game.games.zjh.message.ResBetMsg;
import com.idealighter.game.games.zjh.message.ResChipsChangeMsg;
import com.idealighter.game.games.zjh.message.ResDealCardsMsg;
import com.idealighter.game.games.zjh.message.ResDiscardMsg;
import com.idealighter.game.games.zjh.message.ResEnterGameHallMsg;
import com.idealighter.game.games.zjh.message.ResEnterRoomMsg;
import com.idealighter.game.games.zjh.message.ResEnterTableMsg;
import com.idealighter.game.games.zjh.message.ResExitRoomMsg;
import com.idealighter.game.games.zjh.message.ResExitTableMsg;
import com.idealighter.game.games.zjh.message.ResFastEnterTableMsg;
import com.idealighter.game.games.zjh.message.ResGameInfoMsg;
import com.idealighter.game.games.zjh.message.ResGameOverMsg;
import com.idealighter.game.games.zjh.message.ResOtherEnterTableMsg;
import com.idealighter.game.games.zjh.message.ResReadyMsg;
import com.idealighter.game.games.zjh.message.ResReadyOverMsg;
import com.idealighter.game.games.zjh.message.ResRobotSeeCardMsg;
import com.idealighter.game.games.zjh.message.ResSawCardMsg;
import com.idealighter.game.games.zjh.message.ResSeeCardMsg;
import com.idealighter.game.games.zjh.message.ResVersusMsg;
import com.idealighter.game.games.zjh.struct.ZjhCard;
import com.idealighter.game.games.zjh.struct.ZjhRoom;
import com.idealighter.game.games.zjh.struct.ZjhSeat;
import com.idealighter.game.games.zjh.struct.ZjhTable;
import com.idealighter.game.message.core.ResMessage;
import com.idealighter.game.player.manager.PlayerMsgWriter;
import com.idealighter.game.player.struct.Player;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 扎金花消息管理.
 * 
 * @date 2016年6月23日 上午11:02:52
 *
 */
@Singleton
public class ZjhMsgMgr {

  @Inject
  private PlayerMsgWriter msgWriter;
  @Inject
  private ZjhDataMgr dataMgr;
  @Inject
  private ZhajinhuaRoomTypeDic roomTypeDic;

  /**
   * 发送进入游戏大厅消息 .
   */
  public ResMessage sendEnterGameHallMsg() {
    ResEnterGameHallMsg msg = new ResEnterGameHallMsg();

    Collection<ZjhRoom> rooms = dataMgr.newestRooms();
    for (ZjhRoom room : rooms) {
      ZhajinhuaRoomDomain roomDom = room.getRoomDomain();
      if (roomDom.getIsActive() != 1) {
        continue;
      }
      RoomTypeDetailInfo roomTypeDetailInfo = new RoomTypeDetailInfo();

      roomTypeDetailInfo.setType(roomDom.getType());
      roomTypeDetailInfo.setTypeName(roomTypeDic.map().get(roomDom.getType()).getName());

      RoomInfo roomInfo = toRoomInfo(room);

      roomTypeDetailInfo.getRooms().add(roomInfo);

      msg.getRoomTypes().add(roomTypeDetailInfo);
    }

    return msg;
  }

  /**
   * 房间状态，空闲,普通,拥挤,爆满 .
   * 
   * @param room .
   * @return
   */
  private RoomState roomStatus(ZjhRoom room) {
    int playersNum = room.getPlayers().size();
    ZhajinhuaRoomDomain roomDom = room.getRoomDomain();

    if (playersNum < roomDom.getMaxNum() * roomDom.getFree() / 100) {
      return RoomState.IDLE;
    } else if (playersNum < roomDom.getMaxNum() * roomDom.getGeneral() / 100) {
      return RoomState.GENERAL;
    } else if (playersNum < roomDom.getMaxNum() * roomDom.getCrowded() / 100) {
      return RoomState.CROWD;
    } else {
      return RoomState.FULL;
    }
  }

  /**
   * 发送游戏最新消息 .
   * 
   * @param seat 座位信息.
   * @return 最新信息.
   */
  public ResMessage sendGameLastInfo(ZjhSeat seat) {
    ResGameInfoMsg msg = new ResGameInfoMsg();
    AbstractRoom room = seat.getTable().room();
    List<MemInfo> mems = new ArrayList<>();
    for (Long playerId : seat.getTable().players()) {
      mems.add(room.memInfo(playerId));
    }
    msg.setMems(mems);
    msg.setRoom(toRoomInfo(seat.getTable().getRoom()));
    msg.setGameInfo(toGameInfo(seat));
    return msg;
  }

  private RoomInfo toRoomInfo(ZjhRoom room) {
    RoomInfo roomInfo = new RoomInfo();
    ZhajinhuaRoomDomWrapper roomDom = room.getRoomDomain();
    roomInfo.setRoomId(room.getId().intValue());
    roomInfo.setName(roomDom.getName());
    roomInfo.setType(roomDom.getType());
    roomInfo.setMaxNum(roomDom.getMaxNum());
    roomInfo.setFree(roomDom.getFree());
    roomInfo.setGeneral(roomDom.getGeneral());
    roomInfo.setCrowded(roomDom.getCrowded());
    roomInfo.setLower(roomDom.getLower());
    roomInfo.setUpper(roomDom.getUpper());
    roomInfo.setProportionGold(roomDom.getProportionGold());
    roomInfo.setProportionChips(roomDom.getProportionChips());
    roomInfo.setTabble(roomDom.getTableNum());
    roomInfo.setMaxOne(roomDom.getMaxOne());
    roomInfo.setMinOne(roomDom.getMinOne());
    roomInfo.setAfee(roomDom.getAfee());
    roomInfo.setInType(roomDom.getInType());
    roomInfo.setPlayerNum(room.getPlayers().size());
    roomInfo.setStatus(roomStatus(room).desc);
    roomInfo.setDisplayNames(roomDom.getDisplays());
    roomInfo.setPlaceHolder(roomDom.getPlaceHolder());

    roomInfo.setBase(roomDom.getBase());
    roomInfo.setTop(roomDom.getTop());
    roomInfo.setChip1(roomDom.getChip1());
    roomInfo.setChip2(roomDom.getChip2());
    roomInfo.setChip3(roomDom.getChip3());
    return roomInfo;
  }

  private GameInfo toGameInfo(ZjhSeat mySeat) {
    ZjhTable table = mySeat.getTable();
    GameInfo result = new GameInfo();
    result.setStage(gameStage(table));

    List<PlayerItem> playerInfoList = new ArrayList<PlayerItem>();
    MySelfCard mySelfCard = null;

    List<ZjhSeat> seats = table.getSeats();
    for (ZjhSeat seat : seats) {
      if (seat.getPlayerId() > 0) {
        PlayerItem resultItem = new PlayerItem();
        // 座位顺序
        resultItem.setOrder(seat.getOrder());
        // 玩家状态
        int status = PlayerStatus.OK;
        if (seat.isDiscard()) {
          status = PlayerStatus.DISCARD;
        } else if (seat.isOver()) {
          status = PlayerStatus.OVER;
        }
        resultItem.setStatus(status);
        // 玩家是否准备
        resultItem.setReady(seat.readied() ? 1 : 0);
        // 玩家下注金币
        resultItem.setTotalBetChips(seat.getBetedchips());
        resultItem.setSeeCard(seat.isSawCard() ? 1 : 0);
        playerInfoList.add(resultItem);

        if (seat.getPlayerId() == mySeat.getPlayerId() && seat.isSawCard()) {
          mySelfCard = new MySelfCard();
          mySelfCard.setCardsType(seat.getCards().getType().getPower());
          for (ZjhCard card : seat.getCards().getCards()) {
            mySelfCard.getCards().add(card.ordinal());
          }
        }
      }
    }
    // 准备列表
    result.setPlayerInfoList(playerInfoList); // 玩家信息列表
    // 下一个操作的用户编号
    if (table.getNextOptSeat() != null) {
      result.setNextOpsPlayer(table.getNextOptSeat().getPlayerId());
    }
    result.setPreBet(table.getPreBet()); // 上一个玩家下注筹码数
    result.setPreDardk(table.isPreDark() ? 1 : 0); // 上一个玩家是否暗柱
    result.setTotalBetChips(table.getTotalBetChips());
    result.setMySelfCard(mySelfCard);
    return result;
  }

  /**
   * 游戏阶段.
   * 
   * @author houdongsheng
   * @date 2018年3月14日 下午1:58:53
   * @param table 桌子
   * @return int(0:准备阶段，1：第一轮下注阶段, 2:未超过top的下注阶段, 3:超过top阶段)
   */
  private int gameStage(ZjhTable table) {
    if (!table.isReadied()) { // 正在准备阶段（结束）
      return TableStage.READY_STAGE;
    } else {
      for (ZjhSeat s : table.getSeats()) {
        if (s.getPlayerId() > 0 && !s.isOver() && s.getBetedchips() == 0) {
          return TableStage.FIRST_ROUND_BET_STAGE;
        }
      }

      if (table.getTotalBetChips() >= table.getRoom().getRoomDomain().getTop()) {
        return TableStage.OVER_BET_STAGE_STAGE;
      }
      return TableStage.OTHER_ROUND_BET_STAGE;
    }
  }

  private static class TableStage {
    public static final int READY_STAGE = 0; // 准备阶段
    public static final int FIRST_ROUND_BET_STAGE = 1; // 第一轮下注阶段
    public static final int OTHER_ROUND_BET_STAGE = 2; // 其他下注阶段
    public static final int OVER_BET_STAGE_STAGE = 3; // 下注超过限制阶段
  }

  /**
   * 发送兑换筹码消息 .
   * 
   * @param seat 座位信息.
   */
  public void sendChipsChangeMsg(ZjhSeat seat) {
    ResChipsChangeMsg msg = new ResChipsChangeMsg();
    msg.setChips(seat.getTotalChips());
    msg.setOrder(seat.getOrder());
    sendTablePlayersMsg(seat.getTable(), msg);
  }

  /**
   * 向同桌的玩家发送该座位的玩家已经准备好 .
   * 
   * @param seat 座位信息.
   */
  public void sendReadyMsg(ZjhSeat seat) {
    ResReadyMsg msg = new ResReadyMsg();
    msg.setOrder(seat.getOrder());
    msg.setPlayerId(seat.getPlayerId());
    sendTablePlayersMsg(seat.getTable(), msg);
  }

  /**
   * 发送下注结果消息 .
   * 
   * @param seat 座位信息.
   * @param chips 筹码.
   * @param totalBetChips 总筹码.
   */
  public void sendBetMsg(ZjhSeat seat, long chips, long totalBetChips) {
    ResBetMsg msg = new ResBetMsg();
    msg.setPlayerId(seat.getPlayerId());
    msg.setOrder(seat.getOrder());
    msg.setType(seat.isSawCard() ? 1 : 0);
    msg.setChips(chips);
    msg.setTotalBetChips(totalBetChips);

    ZjhSeat nextOptSeat = seat.getTable().getNextOptSeat();
    msg.setNextOptOrder(nextOptSeat.getOrder());
    msg.setNextOptPlayerId(nextOptSeat.getPlayerId());
    sendTablePlayersMsg(seat.getTable(), msg);
  }

  /**
   * 发送快速进入结果消息 .
   * 
   * @param player 玩家.
   * @param res 0:成功,1:没有空位置
   */
  public void sendFastEnterTableMsg(Player player, int res) {
    ResFastEnterTableMsg msg = new ResFastEnterTableMsg();
    msg.setRes(res);
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 发送进入桌子消息 .
   * 
   */
  public ResMessage sendEnterRoomMsg(ZjhRoom room) {
    ResEnterRoomMsg msg = new ResEnterRoomMsg();
    for (AbstractTable table : room.tables()) {
      msg.getTables().add(table.tableInfo());
    }
    msg.setMembers(room.memInfos());
    return msg;
  }

  /**
   * 发送进入桌子消息 .
   * 
   * @param player 玩家.
   * @param table .
   */
  public void sendEnterTableMsg(Player player, AbstractTable table, long totalChips) {
    ResEnterTableMsg msg = new ResEnterTableMsg();
    AbstractRoom room = table.room();
    List<MemInfo> mems = new ArrayList<>();
    for (Long playerId : table.players()) {
      mems.add(room.memInfo(playerId));
    }
    msg.setMems(mems);
    msg.setTotalChips(totalChips);
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 发送退出房间消息 .
   * 
   * @param player 玩家.
   */
  public void sendExitRoomMsg(Player player) {
    ResExitRoomMsg msg = new ResExitRoomMsg();
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 发送退出桌子消息 .
   * 
   * @param seat 座位信息.
   */
  public void sendExitTableMsg(ZjhSeat seat) {
    ResExitTableMsg msg = new ResExitTableMsg();
    msg.setOrder(seat.getOrder());
    msg.setPlayerId(seat.getPlayerId());
    sendTablePlayersMsg(seat.getTable(), msg);
  }

  /**
   * 发牌 .
   * 
   * @param seat 座位信息.
   */
  public void sendDealCardsMsg(ZjhSeat seat) {
    ResDealCardsMsg msg = new ResDealCardsMsg();
    msgWriter.writeMsg(seat.getPlayerId(), msg);
  }

  /**
   * 发送其他人进入桌子消息 .
   * 
   * @param seat 座位信息.
   */
  public void sendOtherEnterTableMsg(ZjhSeat seat) {
    ResOtherEnterTableMsg msg = new ResOtherEnterTableMsg();
    msg.setMem(seat.getTable().getRoom().memInfo(seat.getPlayerId()));
    for (Long playerId : seat.getTable().players()) {
      if (playerId != seat.getPlayerId()) {
        msgWriter.writeMsg(playerId, msg);
      }
    }
  }

  /**
   * 发送全部准备消息 .
   * 
   * @param table .
   */
  public void sendReadyOverMsg(ZjhTable table) {
    ResReadyOverMsg msg = new ResReadyOverMsg();
    msg.setNextOptOrder(table.getNextOptSeat().getOrder());
    msg.setNextOptPlayerId(table.getNextOptSeat().getPlayerId());
    sendTablePlayersMsg(table, msg);
  }

  /**
   * 向牌中的玩家发送游戏结束消息 .
   * 
   * @param table .
   */
  public void sendGameOver(ZjhTable table) {
    ResGameOverMsg msg = new ResGameOverMsg();
    msg.setBillInfos(new ArrayList<>(table.getBillInfos().values()));
    sendTablePlayersMsg(table, msg);
  }

  /**
   * 发送 .
   * 
   * @param seat 座位信息.
   */
  public void sendSeeCardMsg(ZjhSeat seat) {
    ResSeeCardMsg msg = new ResSeeCardMsg();

    for (ZjhCard card : seat.getCards().getCards()) {
      msg.getCards().add(card.ordinal());
    }

    msg.setCardsType(seat.getCards().getType().getPower());
    msgWriter.writeMsg(seat.getPlayerId(), msg);
  }

  /**
   * 发送机器人看牌消息 .
   * 
   * @param seat 座位信息.
   */
  public void sendRobotSeeCardMsg(ZjhSeat seat) {
    ResRobotSeeCardMsg msg = new ResRobotSeeCardMsg();
    msg.setWin(seat.getCards() == seat.getTable().getMaxCards() ? 1 : 0);
    for (ZjhCard card : seat.getCards().getCards()) {
      msg.getCards().add(card.ordinal());
    }

    msg.setCardsType(seat.getCards().getType().getPower());
    msgWriter.writeMsg(seat.getPlayerId(), msg);
  }

  /**
   * 发送玩家已经看过牌消息 .
   * 
   * @param seat 座位信息.
   */
  public void sendSawCardMsg(ZjhSeat seat) {
    ResSawCardMsg msg = new ResSawCardMsg();
    msg.setOrder(seat.getOrder());
    msg.setPlayerId(seat.getPlayerId());
    sendTablePlayersMsg(seat.table(), msg);
  }

  /**
   * 发送玩家弃牌消息 .
   * 
   * @param seat 座位信息.
   */
  public void sendDiscardMsg(ZjhSeat seat, int nextOptOrder, long nextOptPlayerId) {
    ResDiscardMsg msg = new ResDiscardMsg();
    msg.setOrder(seat.getOrder());
    msg.setPlayerId(seat.getPlayerId());
    msg.setNextOptOrder(nextOptOrder);
    msg.setNextOptPlayerId(nextOptPlayerId);
    sendTablePlayersMsg(seat.table(), msg);
  }

  /**
   * 比牌 .
   * 
   * @param seat 座位信息.
   * @param otherSeat .
   * @param win .
   * @param nextSeat .
   */
  public void sendVersusMsg(ZjhSeat seat, ZjhSeat otherSeat, boolean win, ZjhSeat nextSeat,
      long totalBetChips) {
    ResVersusMsg msg = new ResVersusMsg();
    msg.setWin(win ? 1 : 0);
    msg.setPlayerId(seat.getPlayerId());
    msg.setVsPlayerId(otherSeat.getPlayerId());
    msg.setTotalBetChips(totalBetChips);
    if (nextSeat != null) {
      msg.setNextOptOrder(nextSeat.getOrder());
      msg.setNextOptPlayerId(nextSeat.getPlayerId());
    } else {
      msg.setNextOptOrder(-1);
      msg.setNextOptPlayerId(0);
    }
    sendTablePlayersMsg(seat.getTable(), msg);
  }

  /**
   * 向同桌的玩家(包括自己)发送消息 .
   * 
   * @param table .
   * @param msg .
   */
  public void sendTablePlayersMsg(ZjhTable table, ResMessage msg) {
    List<? extends AbstractSeat> seats = table.seats();
    for (int i = 0; i < seats.size(); i++) {
      AbstractSeat seat = seats.get(i);
      long playerId = seat.getPlayerId();
      if (playerId > 0) {
        msgWriter.writeMsg(playerId, msg);
      }
    }
  }

}
